package com.lestar.htmlparser;

import org.htmlparser.NodeFilter;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;

import java.util.ArrayList;

/**
 * Created by Ray on 2016/10/11.
 */

public class DeepFilter {

    private ArrayList<NodeFilter> depthFilters;
    private ArrayList<Boolean> isDeepMatchers;
    private int depth;

    private DeepFilter(ArrayList<NodeFilter> deepFilters, ArrayList<Boolean> isDeepMatcher) {
        this.depthFilters = deepFilters;
        this.isDeepMatchers = isDeepMatcher;
        this.depth = 0;
    }

    public static InitBuilder init(){
        return new InitBuilder();
    }

    public NodeFilter getFilter(){
        return depthFilters.get(depth);
    }

    public boolean goDeeper(){
        depth++;
        return depth < depthFilters.size();
    }

    public boolean isDeepMatch(){
        return isDeepMatchers.get(depth);
    }

    public static abstract class Builder{

        ArrayList<NodeFilter> depthFilters;
        ArrayList<Boolean> isDeepMatchers;

        public Builder() {
            this.depthFilters = new ArrayList<>();
            this.isDeepMatchers = new ArrayList<>();
        }

        public static TagFilterBuilder getTagFilter(){
            return new TagFilterBuilder();
        }

        public static OrFilter getOrFilter(NodeFilter...filters){
            return new OrFilter(filters);
        }

        public static class TagFilterBuilder {

            ArrayList<NodeFilter> filters;

            public TagFilterBuilder() {
                filters = new ArrayList<>();
            }

            public TagFilterBuilder name(String name){
                filters.add(new TagNameFilter(name));
                return this;
            }

            public TagFilterBuilder attribute(String name, String value){
                filters.add(new HasAttributeFilter(name, value));
                return this;
            }

            public TagFilterBuilder attributeRegex(String name, String regex){
                filters.add(new HasRegexAttrFilter(name, regex));
                return this;
            }

            public NodeFilter create(){
                return new AndFilter(filters.toArray(new NodeFilter[filters.size()]));
            }
        }
    }

    public static class InitBuilder extends Builder{

        private InitBuilder() {
            super();
        }

        private InitBuilder(ArrayList<NodeFilter> deepFilters, ArrayList<Boolean> isDeepMatchers) {
            this.depthFilters = deepFilters;
            this.isDeepMatchers = isDeepMatchers;
        }

        public NextBuilder match(NodeFilter filter){
            return new NextBuilder(filter, false, this);
        }

        public NextBuilder deepMatch(NodeFilter filter){
            return new NextBuilder(filter, true, this);
        }
    }

    public static class NextBuilder extends Builder{

        NodeFilter filter;
        boolean deepMatch;

        private NextBuilder(NodeFilter filter, boolean deepMatch, InitBuilder initBuilder) {
            this.filter = filter;
            this.deepMatch = deepMatch;
            this.depthFilters = initBuilder.depthFilters;
            this.isDeepMatchers = initBuilder.isDeepMatchers;
        }

        public NextBuilder or(NodeFilter filter){
            this.filter = getOrFilter(this.filter, filter);
            return this;
        }

        public InitBuilder deeper(){
            depthFilters.add(filter);
            isDeepMatchers.add(deepMatch);
            return new InitBuilder(depthFilters, isDeepMatchers);
        }

        public DeepFilter create(){
            depthFilters.add(filter);
            isDeepMatchers.add(deepMatch);
            return new DeepFilter(depthFilters, isDeepMatchers);
        }
    }
}
